#include <Eratostenes.hpp>

Eratostenes::Eratostenes(unsigned n) : n(n) {
	// The sieve contains only the odd numbers
	sieveSz = ((n + 1) / 2) + (!(n&1));
	// The sieve wasn't calculated yet
	calculated = false;
	sieve = new bool[sieveSz];	
}

Eratostenes::~Eratostenes() {
	delete [] sieve;
}

void Eratostenes::calculate(long long *icount, unsigned nThreads) {
	// If the sieve was already calculated, return
	if (calculated) return;
	calculated = true;
	long long myicount = 0L;

	// The number 1 (index 1 / 2 = 0) isn't prime
	sieve[0] = false;

	// All odd numbers are considered primes by now
	for (int i = 1; i <= sieveSz; i++, myicount += 3L)
		sieve[i] = true;

	// Navigates through the odd numbers numbers 
	for (int i = 3; i * i <= n; i += 2, myicount += 3L)
		// if the current number is confirmated as prime number
		if (sieve[i>>1])
			// Navigates through its odd multiples and marks them as non-prime
			for (int j = i * i, k = i<<1; j <= n; j += k, myicount += 3L)
				sieve[j>>1] = false;

	if(icount) *icount += myicount;

}

bool Eratostenes::operator[](const unsigned number) const {
	if(!calculated) throw "Eratostenes error: "
		"need to calculate first";
	if(!(number&1)) return number == 2; // Only the number 2 is even and prime
	if(number > n) throw "Eratostenes error: out of bound";
	return sieve[number>>1];
}
